package jp.co.hcs.attendancemanagement.inputdailyattendance.logic;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;

import jp.co.hcs.attendancemanagement.AMConstants;
import jp.co.hcs.attendancemanagement.AMResourceKeyConstants;
import jp.co.hcs.attendancemanagement.AMResourceManager;
import jp.co.hcs.attendancemanagement.StrutsMessageConstants;
import jp.co.hcs.attendancemanagement.common.ApprovalRecordData;
import jp.co.hcs.attendancemanagement.common.ApprovalRecordRegister;
import jp.co.hcs.attendancemanagement.data.entity.EffortActual;
import jp.co.hcs.attendancemanagement.data.entity.Job;
import jp.co.hcs.attendancemanagement.data.entity.PositionMaster;
import jp.co.hcs.attendancemanagement.data.entity.RestTime;
import jp.co.hcs.attendancemanagement.data.entity.WorkingTimeActual;
import jp.co.hcs.attendancemanagement.exception.AMSQLException;
import jp.co.hcs.attendancemanagement.inputdailyattendance.actionform.InputDailyAttendanceForm;
import jp.co.hcs.attendancemanagement.inputdailyattendance.logic.dto.DailyWorkingActualResultDTO;
import jp.co.hcs.attendancemanagement.inputdailyattendance.logic.dto.EmployeeCompanyDTO;
import jp.co.hcs.attendancemanagement.inputdailyattendance.logic.dto.ProjectInfoDTO;
import jp.co.hcs.attendancemanagement.inputdailyattendance.logic.dto.RestTimeDTO;
import jp.co.hcs.attendancemanagement.inputdailyattendance.logic.dto.StampActualResultDTO;
import jp.co.hcs.attendancemanagement.util.DateUtil;
import jp.co.hcs.attendancemanagement.util.StringUtil;
import jp.co.hcs.attendancemanagement.util.TimeUtil;

import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;

public class SaveDailyWorkingLogic extends InputDailyWorkingLogicBase {
    /**
     * Save daily working.
     * 
     * @param form
     *            the form
     * @return the action messages
     * @throws SQLException
     *             the sQL exception
     * @throws AMSQLException
     */
    public ActionMessages saveDailyWorking(InputDailyAttendanceForm form)
            throws AMSQLException {
        ActionMessages errors = new ActionMessages();

        String dailyTakeLeaveNo;
        String dailySubstituteLeaveAddingNo;
        boolean fullRestFlag = false;
        String nonWorkingTime = TimeUtil.TIME_EMPTY;

        try {
            daoFactory.startTransaction();

            List<ProjectInfoDTO> projectEffortList = form
                    .getProjectInfoDTOList();

            // check project list info
            for (ProjectInfoDTO projectDto : projectEffortList) {
                // check existing of project code and work code
                checkProjectCode(projectDto.getProjectCode(),
                        projectDto.getSeri(), errors);
                checkWorkCode(projectDto.getWorkCode(), errors);

                // working time is required
                if (TimeUtil.isTimeEmpty(projectDto.getWorkingTime())) {
                    errors.add(
                            ActionErrors.GLOBAL_MESSAGE,
                            new ActionMessage(
                                    StrutsMessageConstants.ALARM_W1052_ERROR,
                                    AMResourceManager
                                            .getMessage(AMResourceKeyConstants.FIELD_OPERATIONTIME)));
                    return errors;
                }
            }

            // check project code and work code duplicate
            ProjectInfoDTO projectObj1;
            ProjectInfoDTO projectObj2;
            for (int i = 0; i < projectEffortList.size() - 1; i++) {
                projectObj1 = projectEffortList.get(i);
                for (int j = i + 1; j < projectEffortList.size(); j++) {
                    projectObj2 = projectEffortList.get(j);
                    if (projectObj1.equals(projectObj2)) {
                        errors.add(
                                ActionErrors.GLOBAL_MESSAGE,
                                new ActionMessage(
                                        StrutsMessageConstants.ALARM_W1096_ERROR,
                                        AMResourceManager
                                                .getMessage(AMResourceKeyConstants.MSG_PROJECTEFFORTDUPLICATE)));
                        return errors;
                    }
                }
            }

            DailyWorkingActualResultDTO dailyWorking = form.getTimeDTO();

            roundWorkingTimeInfo(dailyWorking);

            // edit daily working status
            dailyWorking
                    .setDailyWorkingApprovalStatus(StringUtil.EDITING_VALUE);

            // --get job division
            String jobType = dailyWorking.getJobDivision();

            StampActualResultDTO stampActual = form.getStampActualResultDTO();

            // check before saving
            if (AMConstants.HOLIDAY_WORKING.equals(jobType)) {
                if (!StringUtil.isEmpty(form.getSubstituteHoliday())) {
                    // --phan doan gia tri flag nghi bu day du
                    EmployeeCompanyDTO employeeInfo = form.getInitDTO();
                    PositionMaster position = getPositionMasterDAO()
                            .getPositionByIdWithFullRest(
                                    employeeInfo.getPositionCode());
                    if (position != null) {
                        fullRestFlag = true;
                    }
    
                    Job attendanceClassification = getJobDAO().selectJobByPrimaryKey(jobType);
                    float minRestHoliday = attendanceClassification
                            .getTransferHolidayTimeMin().floatValue();
                    float maxRestHoliday = attendanceClassification
                            .getTransferHolidayTimeMax().floatValue();
                    String workingTime = dailyWorking.getWorkingTime();
                    String substituteHolidayTime = dailyWorking
                            .getSubstituteHolidayTime();
                    // --check ngay nghi bu
                    if (fullRestFlag) {
                        if (!TimeUtil.isEqual(substituteHolidayTime, workingTime)) {
                            errors.add(
                                    ActionErrors.GLOBAL_MESSAGE,
                                    new ActionMessage(
                                            StrutsMessageConstants.ALARM_W1053_ERROR,
                                            AMResourceManager
                                                    .getMessage(AMResourceKeyConstants.FIELD_SUBSTITUTEHOLIDAYTIME)));
                            return errors;
                        }
                    } else {
                        if (minRestHoliday > TimeUtil
                                .convertTimeFromHHMM(workingTime)) {
                            errors.add(
                                    ActionErrors.GLOBAL_MESSAGE,
                                    new ActionMessage(
                                            StrutsMessageConstants.ALARM_W1055_ERROR,
                                            AMResourceManager
                                                    .getMessage(AMResourceKeyConstants.FIELD_SUBSTITUTEHOLIDAY)));
                            return errors;
                        }
    
                        float substituteHolidayTimeConverted = TimeUtil
                                .convertTimeFromHHMM(substituteHolidayTime);
                        if (!(minRestHoliday <= substituteHolidayTimeConverted && substituteHolidayTimeConverted <= maxRestHoliday)) {
                            errors.add(
                                    ActionErrors.GLOBAL_MESSAGE,
                                    new ActionMessage(
                                            StrutsMessageConstants.ALARM_W1053_ERROR,
                                            AMResourceManager
                                                    .getMessage(AMResourceKeyConstants.FIELD_SUBSTITUTEHOLIDAYTIME)));
                            return errors;
                        }
                    }
                }
                else {
                    errors.add(
                            ActionErrors.GLOBAL_MESSAGE,
                            new ActionMessage(
                                    StrutsMessageConstants.ALARM_W1098_ERROR,
                                    AMResourceManager
                                            .getMessage(AMResourceKeyConstants.FIELD_SUBSTITUTEHOLIDAY)));
                    return errors;
                }
            }

            // --check thoi gian lam ca, overtime
            // --error W1053
            if (TimeUtil.isGreaterThan(dailyWorking.getNightShiftWork(), dailyWorking.getFixedWorkingTime())) {
                errors.add(
                        ActionErrors.GLOBAL_MESSAGE,
                        new ActionMessage(
                                StrutsMessageConstants.ALARM_W1053_ERROR,
                                AMResourceManager
                                        .getMessage(AMResourceKeyConstants.FIELD_OVERWORKINGTIME)));
                return errors;
            }

            String stampStartDay = stampActual.getComingWorkDay();
            String stampStartTime = stampActual.getComingWorkTime();
            String stampEndDay = stampActual.getLeavingWorkDay();
            String stampEndTime = stampActual.getLeavingWorkTime();
            String workingStartTime = dailyWorking.getWorkingStartTime();
            if (!StringUtil.isEmpty(workingStartTime)) {
                workingStartTime = StringUtil
                        .fullWidthNumberToHalfWidthNumber(workingStartTime);
                dailyWorking.setWorkingStartTime(workingStartTime);
            }
            String workingStartDay = dailyWorking.getWorkingStartDay();
            if (!StringUtil.isEmpty(workingStartDay)) {
                workingStartDay = StringUtil
                        .fullWidthNumberToHalfWidthNumber(workingStartDay);
                dailyWorking.setWorkingStartDay(workingStartDay);
            }
            String workingEndTime = dailyWorking.getWorkingEndTime();
            if (!StringUtil.isEmpty(workingEndTime)) {
                workingEndTime = StringUtil
                        .fullWidthNumberToHalfWidthNumber(workingEndTime);
                dailyWorking.setWorkingEndTime(workingEndTime);
            }
            String workingEndDay = dailyWorking.getWorkingEndDay();
            if (!StringUtil.isEmpty(workingEndDay)) {
                workingEndDay = StringUtil
                        .fullWidthNumberToHalfWidthNumber(workingEndDay);
                dailyWorking.setWorkingEndDay(workingEndDay);
            }
            // --edit thoi gian ko lao dong
            if (!StringUtil.isEmpty(stampStartDay)
                    && !StringUtil.isEmpty(stampEndDay)
                    && !StringUtil.isEmpty(workingStartDay)
                    && !StringUtil.isEmpty(workingEndDay)) {
                if (stampStartDay.equals(workingStartDay)
                        && (!stampActual.getChokkoFlag() || !dailyWorking
                                .getCommutingDelayFlag())) {
                    // nonWorkingTime = stamp start time - working start time
                    nonWorkingTime = TimeUtil.sub(stampStartTime,
                            workingStartTime);
                }
                if (DateUtil.isBefore(stampStartDay, workingStartDay)) {
                    // nonWorkingTime = (24:00 - Stamp start time) + Working
                    // start time
                    nonWorkingTime = TimeUtil.sum(
                            TimeUtil.sub("24:00", stampStartTime),
                            workingStartTime);
                }
                if (stampEndDay.equals(workingEndDay)
                        && !stampActual.getChokkiFlag()) {
                    // nonWorkingTime = nonWorkingTime + (stampEndTime -
                    // workingEndTime);
                    nonWorkingTime = TimeUtil.sum(nonWorkingTime,
                            TimeUtil.sub(stampEndTime, workingEndTime));
                }
                if (DateUtil.isBefore(workingEndDay, stampEndDay)) {
                    // nonWorkingTime = nonWorkingTime + (stampEndTime +
                    // ("24:00" - workingEndTime));
                    nonWorkingTime = TimeUtil.sum(
                            nonWorkingTime,
                            TimeUtil.sum(stampEndTime,
                                    TimeUtil.sub("24:00", workingEndTime)));
                }
            }

            String dailyOvertimeTotal = calculateDailyOvertimeTotal(dailyWorking);
            String specialOvertime = calculateSpecialOvertime(dailyWorking);
            
            // update data lam viec/nghi theo ngay
            String employeeId = form.getUserId();
            String yearMonth = form.getYear() + form.getMonth();
            String day = form.getDay();
            WorkingTimeActual workingTimeActual = getWorkingTimeActualDAO()
                    .selectWorkingTimeActualByPrimaryKey(employeeId, day,
                            yearMonth);
            if (workingTimeActual == null) {
                workingTimeActual = new WorkingTimeActual();
                workingTimeActual.setEmployeeId(employeeId);
                workingTimeActual.setActualWorkingYearMonth(yearMonth);
                workingTimeActual.setActualWorkingDay(day);
                workingTimeActual.setRegisterId(employeeId);
                workingTimeActual.setRegisterDate(new Date());
                workingTimeActual.setRegisterTime(new Date());
                copyPropertiesDailyWorking(dailyWorking, workingTimeActual,
                        form.getYear());
                workingTimeActual.setNonWorkingTime(DateUtil.parseDateFromHHmm(nonWorkingTime));
                workingTimeActual.setTotalOvertimePerDay(DateUtil.parseDateFromHHmm(dailyOvertimeTotal));
                workingTimeActual.setSpecialOvertimeTime(DateUtil.parseDateFromHHmm(specialOvertime));
                getWorkingTimeActualDAO().insertWorkingTimeActualSelective(
                        workingTimeActual);
            } else {
                workingTimeActual.setEmployeeId(employeeId);
                workingTimeActual.setActualWorkingYearMonth(yearMonth);
                workingTimeActual.setActualWorkingDay(day);
                workingTimeActual.setChangePersonId(employeeId);
                workingTimeActual.setChangeDate(new Date());
                workingTimeActual.setChangeTime(new Date());
                copyPropertiesDailyWorking(dailyWorking, workingTimeActual,
                        form.getYear());
                workingTimeActual.setNonWorkingTime(DateUtil.parseDateFromHHmm(nonWorkingTime));
                workingTimeActual.setTotalOvertimePerDay(DateUtil.parseDateFromHHmm(dailyOvertimeTotal));
                workingTimeActual.setSpecialOvertimeTime(DateUtil.parseDateFromHHmm(specialOvertime));
                getWorkingTimeActualDAO()
                        .updateWorkingTimeActualByPrimaryKey(workingTimeActual);
            }

            // update data thoi gian nghi giai lao
            // --delete data daily working_rest time
            getRestTimeDAO().deleteRestTimeInDay(employeeId, day, yearMonth);

            // --dang ky data daily working_rest time
            List<RestTimeDTO> restTimeList = form.getRestTimeInfoDTOList();
            if (restTimeList != null) {
                RestTime restObj;
                for (RestTimeDTO restDto : restTimeList) {
                    if (!StringUtil.isEmpty(restDto.getRestStartTime())
                            && !StringUtil.isEmpty(restDto.getRestEndTime())) {
                        restObj = new RestTime();
                        restObj.setEmployeeId(employeeId);
                        restObj.setActualWorkingDay(day);
                        restObj.setActualWorkingYearMonth(yearMonth);
                        restObj.setTakingRestNum((short) restDto
                                .getTakingRestNum());
                        restObj.setRestTime(DateUtil.parseDateFromHHmm(restDto
                                .getRestTime()));
                        restObj.setRestStartTime(DateUtil
                                .parseDateFromHHmm(restDto.getRestStartTime()));
                        restObj.setRestEndTime(DateUtil
                                .parseDateFromHHmm(restDto.getRestEndTime()));
                        restObj.setComment(restDto.getComment());
                        getRestTimeDAO().insertRestTimeSelective(restObj);
                    }
                }
            }

            // update data daily effort actual
            // --delete data daily effort
            getEffortActualDAO().deleteEffortActualInDay(employeeId, day,
                    yearMonth);

            // --dang ky data daily effort actual
            EffortActual effortObj;
            Date now = new Date();
            int seqNo = 0;
            for (ProjectInfoDTO prjInfoDto : projectEffortList) {
                if (!StringUtil.isEmpty(prjInfoDto.getProjectCode())
                        && !StringUtil.isEmpty(prjInfoDto.getSeri())
                        && !StringUtil.isEmpty(prjInfoDto.getWorkCode())
                        && !StringUtil.isEmpty(prjInfoDto.getWorkingTime())) {
                    effortObj = new EffortActual();
                    effortObj.setEmployeeId(employeeId);
                    effortObj.setActualEffortYearMonth(yearMonth);
                    effortObj.setActualEffortDay(day);
                    effortObj.setSeqNo((short) ++seqNo);
                    effortObj.setRegisterId(employeeId);
                    effortObj.setRegisterDate(now);
                    effortObj.setRegisterTime(now);
                    effortObj.setProjectId(prjInfoDto.getProjectNumber());
                    effortObj.setProjectCode(prjInfoDto.getProjectCode());
                    effortObj.setWorkingId(prjInfoDto.getWorkCode());
                    effortObj
                            .setWorkingTime(DateUtil.parseDateFromHHmm(StringUtil
                                    .fullWidthNumberToHalfWidthNumber(prjInfoDto
                                            .getWorkingTime())));
                    effortObj.setComment(prjInfoDto.getComment());
                    getEffortActualDAO().insertEffortActualSelective(effortObj);
                }
            }

            // register data daily working approval
            ApprovalRecordData approvalData = new ApprovalRecordData();
            approvalData.setEmployeeId(employeeId);
            approvalData.setApprovalTypeId(AMConstants.APPROVAL_TYPE_DAILY);
            approvalData.setTargetYearMonth(yearMonth);
            approvalData.setTargetDay(day);
            approvalData.setTimingRegistCode(0);
            approvalData.setDayRegistCode(1);
            approvalData.setEffortRegistCode(1);
            approvalData.setApplicationNo("");
            approvalData.setProgramId(AMConstants.PGM_5031_SCREEN_ID);
            ApprovalRecordRegister approvalRegister = new ApprovalRecordRegister();
            int resultCode = approvalRegister.registerApproval(approvalData);
            if (resultCode == AMConstants.ERROR_FINISH) {
                // rollback
                errors.add(
                        ActionErrors.GLOBAL_MESSAGE,
                        new ActionMessage(
                                StrutsMessageConstants.ALARM_W1061_ERROR,
                                AMResourceManager
                                        .getMessage(AMResourceKeyConstants.ACTION_UPDATEPROCESS)));
                return errors;
            }

            // commit data
            daoFactory.commitTransaction();

        } catch (SQLException e) {
            throw new AMSQLException(e.getMessage());
        } finally {
            try {
                daoFactory.endTransaction();
            } catch (SQLException e) {
                throw new AMSQLException(e.getMessage());
            }
        }

        return errors;
    }

}
